﻿// Created by amoylel on 30/09/2018.
// Copyright (c) 2018 amoylel All rights reserved.

#ifndef AMO_STRING_UTILS_D72E1F7C_8BFA_48BA_A990_6129BC202A86_HPP__
#define AMO_STRING_UTILS_D72E1F7C_8BFA_48BA_A990_6129BC202A86_HPP__


#ifndef AMO_NO_BOOST
#include <amo/string/string_convert_boost.hpp>
#else
#include <amo/string/string_convert_default.hpp>
#endif

namespace amo {
    namespace string_utils {
    
        template<typename T>
        static T to_string(const std::string& atr) {
            return T();
        }
        
        template<> std::string to_string<std::string>(const std::string& atr) {
            return atr;
        }
        template<> std::wstring to_string<std::wstring>(const std::string&
                atr) {
            return ansi_to_wide(atr);
        }
        
        
        template < typename T>
        static std::string to_string_impl(const T& val, int bit, int unit,
                                          char separator = ' ') {
                                          
                                          
            static  std::vector<char> hexes = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
                                                'D', 'E', 'F'
                                              };
                                              
            static std::vector<int8_t> masks = { 0, 0x1, 0x3, 0x7, 0xf };
            
            if (bit < 1 || bit >= masks.size()) {
                return "";
            }
            
            
            
            T mask = masks[bit];
            std::string retval;
            
            int len = sizeof(T) * 8;
            int residual = len % bit;
            
            if (residual > 0) {
                int index = (val & (mask << (len - residual))) >> (len - residual);
                retval += hexes[index];
            }
            
            len -= residual;
            
            
            for (int i = len - bit; i >= 0; i -= bit) {
                int index = (val & (mask << i)) >> i;
                retval += hexes[index];
                
                if (unit > 0 && (i % unit == 0)) {
                    retval += separator;
                }
            }
            
            return retval;
        }
        
        
        
        template < typename T>
        static std::string to_string(const T& val, int base = 10,
                                     int unit = 0,
                                     char separator = ' ') {
            switch (base) {
            case 2:
                return to_string_impl(val, 1, unit, separator);
                
            case 4:
                return to_string_impl(val, 2, unit, separator);
                
            case 8:
                return to_string_impl(val, 3, unit, separator);
                
            case 10:
                return std::to_string(val);
                
            case 16:
                return to_string_impl(val, 4, unit, separator);
                
            default:
                return std::to_string(val);
            }
            
            return "";
        }
        
        template < typename T>
        static std::string to_hex(const T& val, bool prefix = true) {
            if (prefix) {
                return "0x" + to_string(val, 16);
            } else {
                return to_string(val, 16);
            }
        }
        
        template < typename T>
        static std::string to_octal(const T& val, bool prefix = true) {
            if (prefix) {
                return "0" + to_string(val, 8);
            } else {
                return to_string(val, 8);
            }
        }
        
        template < typename T>
        static std::string to_binary(const T& val) {
            return to_string(val, 2);
        }
        
    }
}



#endif //AMO_STRING_UTILS_D72E1F7C_8BFA_48BA_A990_6129BC202A86_HPP__
